package grammar.parser;

import error.processing.MyErrorProcessing;
import exp.parser.ConstExp;
import semantic.parser.SymbolTableElement;
import word.parser.WordElement;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class FuncFParams extends GrammarParser {
    private final List<FuncFParam> params = new ArrayList<>();

    public static FuncFParams buildFuncFParams() {
        FuncFParams params = new FuncFParams();
        do {
            params.params.add(FuncFParam.buildFuncFParam());
            if (getAnalyzingWord().getType() == WordElement.WordType.COMMA) {
                analyzeNextWord();
            } else {
                break;
            }
        } while (true);
        return params;
    }

    public static class FuncFParam {
        private final int dimension;
        private final int len;
        private final String paramName;

        public FuncFParam(int dimension, int len, String paramName) {
            this.dimension = dimension;
            this.len = len;
            this.paramName = paramName;
        }
        public FuncFParam(int dimension, int len) {
            this.dimension = dimension;
            this.len = len;
            this.paramName = null;
        }
        public FuncFParam() {
            this.dimension = 0;
            this.len = 0;
            this.paramName = null;
        }

        public static FuncFParam buildFuncFParam() {
            assert getAnalyzingWord().getType() == WordElement.WordType.INTTK;
            analyzeNextWord();

            assert getAnalyzingWord().getType() == WordElement.WordType.IDENFR;
            String ident = getAnalyzingWord().getWord();
            int identPosition = getNowPosition();
            int dimension = 0;
            int len = 0;
            analyzeNextWord();
            List<Integer> lenOfDimension = new ArrayList<>();
            if (getAnalyzingWord().getType() == WordElement.WordType.LBRACK) {
                analyzeNextWord();
                dimension++;
                lenOfDimension.add(0);
                if (getAnalyzingWord().getType() != WordElement.WordType.RBRACK) {
                    MyErrorProcessing.buildErrorProcessing(MyErrorProcessing.ErrorType.k, getAnalyzingWord(-1));
                } else {
                    analyzeNextWord();
                }
            }
            if (getAnalyzingWord().getType() == WordElement.WordType.LBRACK) {
                dimension++;
                analyzeNextWord();
                len = ConstExp.buildAndCompute().getValue();
                lenOfDimension.add(len);
                if (getAnalyzingWord().getType() != WordElement.WordType.RBRACK) {
                    MyErrorProcessing.buildErrorProcessing(MyErrorProcessing.ErrorType.k, getAnalyzingWord(-1));
                } else {
                    analyzeNextWord();
                }
            }

            getSemanticParser().declVariable(getWord(identPosition),
                    SymbolTableElement.SymbolType.INT, getScope(),
                    dimension, lenOfDimension, null, null);


            FuncFParam param = new FuncFParam(dimension, len, ident);
            return param;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            FuncFParam that = (FuncFParam) o;
            return dimension == that.dimension;
        }

        @Override
        public int hashCode() {
            return Objects.hash(dimension);
        }

        public String getParamName() {
            return paramName;
        }

        public int getDimension() {
            return dimension;
        }

        public int getLen() {
            return len;
        }
    }

    public List<FuncFParam> getParams() {
        return params;
    }
}
